﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;
using ICodeShare.UI.Converters.Common;
using ICodeShare.UI.Converters.Extensions;
using System.Globalization;

namespace ICodeShare.UI.Converters
{
    #region IValueConverter
    /// <summary>
    /// 比较数值型输入转换成Boolean值
    /// </summary>
    /// <example>
    /// 1.在xmal文件引用DateConverter类所在命名空间。
    ///   xmlns:cvts="http://schemas.extended.wpf.com/converters"
    /// 2.在xaml文件添加Resources。
    ///   <Window.Resources>
    ///   <cvts:NumericCompareToBooleanConverter x:Key="cvtsNumericCompareToBoolean"/>
    ///   </Window.Resources>
    /// 3.在xaml文件中指定Binding值的Converter
    ///    <TextBox Text="{Binding Text.Length,ElementName=txtCompare,Converter={StaticResource cvtsNumericCompareToBoolean},ConverterParameter='100',Mode=OneWay}"></TextBox>
    /// </example>
    /// <remarks>
    /// Symbol种类：
    /// 双目比较符包括：Equal,LessThan,GreaterThan,LessThanOrEqual,GreaterThanOrEqual,NotEqual
    /// 三目比较符包括：Between,BetweenOrEqual
    /// 多目比较符包括：StdIn
    /// 参数parameter应该包含该一个参数或多个以分号(;)分隔的参数.
    /// 如果参数parameter只包含一个参数时，这个参数表示双目比较符的比较对象。
    /// 如果参数parameter包含两个以上参数时，第一个参数表示三目比较符的下限值，第二个字符串表示双目比较符的比较对象或三目比较符的上限值。
    /// 进行StdIn比较时，参数parameter表示一组枚举值。
    /// 如果参数parameter未声明，则总返回false.
    /// </remarks>
    [ValueConversion(typeof(object), typeof(Boolean))]
    public class NumericCompareToBooleanConverter : IValueConverter
    {
        #region  Members 成员变量
        private NCompareSymbol _symbol = NCompareSymbol.Equal;
        #endregion

        #region Constructors 构造函数
        /// <summary>
        /// Initializes a new instance of the CaseConverter class.
        /// </summary>
        public NumericCompareToBooleanConverter()
        {
          
        }

        /// <summary>
        /// Initializes a new instance of the CaseConverter class with the specified source and target casings.
        /// </summary>
        /// <param name="casing">
        /// The source and target casings for the converter (see <see cref="Casing"/>).
        /// </param>
        public NumericCompareToBooleanConverter(NCompareSymbol symbol)
        {
            this.Symbol = symbol;
        }
        #endregion

        #region  Properties 属性
        /// <summary>
        /// 比较运算符号
        /// </summary>
        [ConstructorArgument("symbol")]
        public NCompareSymbol Symbol
        {
            get
            {
                return this._symbol;
            }

            set
            {
                value.AssertEnumMember("value", NCompareSymbol.Equal, NCompareSymbol.LessThan, NCompareSymbol.GreaterThan,
                    NCompareSymbol.LessThanOrEqual, NCompareSymbol.GreaterThanOrEqual, NCompareSymbol.NotEqual,
                    NCompareSymbol.Between,NCompareSymbol.BetweenOrEqual, NCompareSymbol.StdIn);
                this._symbol = value;
            }
        }
        #endregion

        #region  Base Class Overrides 基类方法重写
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            //只有数值型才能进行比较
            if (!IsNumericType(value.GetType())) return false;

            bool result = false;
            IComparable sourceValue = (IComparable)value;
            if (sourceValue == null)
            {
                result = false;
            }
            IComparable targetValue, lowerValue;
            IEnumerable<IComparable> rangeValues;
            ParseParameter(parameter, sourceValue, culture, out lowerValue, out targetValue, out rangeValues);
            switch (Symbol)
            {
                case NCompareSymbol.Equal: { 
                    result = sourceValue.CompareTo(targetValue) == 0; 
                    break; 
                }
                case NCompareSymbol.LessThan: { 
                    result = sourceValue.CompareTo(targetValue) < 0; 
                    break; 
                }
                case NCompareSymbol.GreaterThan: { 
                    result = sourceValue.CompareTo(targetValue) > 0; 
                    break; 
                }
                case NCompareSymbol.LessThanOrEqual: { 
                    result = sourceValue.CompareTo(targetValue) <= 0; 
                    break; 
                }
                case NCompareSymbol.GreaterThanOrEqual: { 
                    result = sourceValue.CompareTo(targetValue) >= 0; 
                    break;
                }
                case NCompareSymbol.NotEqual: { 
                    result = sourceValue.CompareTo(targetValue) != 0; 
                    break; 
                }
                case NCompareSymbol.Between: {
                     result = (sourceValue.CompareTo(lowerValue)>0 && sourceValue.CompareTo(targetValue)<0); 
                    break;
                }
                case NCompareSymbol.BetweenOrEqual:
                    {
                        result = (sourceValue.CompareTo(lowerValue) >= 0 && sourceValue.CompareTo(targetValue) <= 0); 
                        break;
                    }
                case NCompareSymbol.StdIn: {
                    if (rangeValues == null)
                    {
                        result = false;
                    }
                    else
                    {
                        result = rangeValues.Contains(sourceValue);
                    }
                    break;
                }
                default: break;
            }

            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Methods 方法
        private void ParseParameter<T>(object parameter, T value, CultureInfo culture, out IComparable lowerValue, out IComparable targetValue, out IEnumerable<IComparable> rangeValues) where T : IComparable
        {
            lowerValue = default(T);
            targetValue = default(T);
            rangeValues = null;
            var stringValue = parameter as string;
            if (string.IsNullOrWhiteSpace(stringValue))
                return;
            var stringValues = stringValue.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            if (stringValues.Length == 0)
                return;
            rangeValues = stringValues.Select(x => (IComparable)System.Convert.ChangeType(x, value.GetType(), culture));

            if (stringValues.Length == 1)
            {
                targetValue = (IComparable)System.Convert.ChangeType(stringValues[0], value.GetType(), culture);
            }
            else if (stringValues.Length >= 2)
            {
                lowerValue = (IComparable)System.Convert.ChangeType(stringValues[0], value.GetType(), culture);
                targetValue = (IComparable)System.Convert.ChangeType(stringValues[1], value.GetType(), culture);
               
            }
            else
            { 
            }
        }

        public  bool IsNumericType(Type type)
        {
            if (type == null)
            {
                return false;
            }

            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Byte:
                case TypeCode.Decimal:
                case TypeCode.Double:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.SByte:
                case TypeCode.Single:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return true;

                case TypeCode.Object:
                    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        return IsNumericType(Nullable.GetUnderlyingType(type));
                    }
                    return false;
            }
            return false;
        }
        #endregion

    }
    #endregion
}
